/*
 * Borovicska Szglab4 2011
 * @package circuit1
 */
package circuit1;

import java.io.*;
import java.util.ArrayList;

/**
 * InputController
 * @author Gergely Hernesz <herneszg@gmail.com>
 */
public class InputController extends Controller {

    YamlAdapter adapter;

    /**
     * Program belepesi pont
     * @param args 
     */
    public static void main(String[] args) {
        System.setOut(new OutputHandler(args[1]));
        Controller c = new InputController(args[0]);
    }

    /**
     * Konstruktor, ami input fajl alapjan elinditja a mukodest
     * @param inputFile 
     */
    public InputController(String inputFile) {
        try {
            FileInputStream fstream = new FileInputStream(inputFile);
            DataInputStream in = new DataInputStream(fstream);
            BufferedReader br = new BufferedReader(new InputStreamReader(in));
            String line;
            while ((line = br.readLine()) != null) {
                String cmd = getCommandByInputLine(line);
                String[] params = getCmdParametersByInputLine(line);
                handleCmd(cmd, params);
            }
            in.close();
        } catch (Exception e) {
            System.err.println("\nError: " + e);
        }
    }

    /**
     * Az inputfile egy sorabol visszaadja a parancsot
     * @param line
     * @return 
     */
    private String getCommandByInputLine(String line) {
        String[] cmds = line.split("\\s+");
        return cmds[0];
    }

    /**
     * Az inputfile egy sorabol visszaadja a parancs parametereit
     * @param line
     * @return 
     */
    private String[] getCmdParametersByInputLine(String line) {
        String[] cmds = line.split("\\s+");
        return java.util.Arrays.copyOfRange(cmds, 1, cmds.length);
    }

    /**
     * Lekezeli, majd vegrehajtja a parancsot
     * @param cmd
     * @param params 
     */
    private void handleCmd(String cmd, String[] params) {
        if (cmd.equals("loadcircuit")) {
            adapter = new YamlAdapter(params[0]);
        } else if (cmd.equals("exit")) {
            System.exit(0);
        } else if (cmd.equals("tick")) {
            tickAll(Integer.valueOf(params[0]));
        } else if (cmd.equals("switch")) {
            Switch sw = (Switch) adapter.getCircuit().getElementById(params[0]);
            if (sw == null) {
                System.out.println(params[0] + " nevu kapcsolo nem letezik");
                System.exit(1);
            }
            if (params[1].equals("on")) {
                sw.on();
            } else if (params[1].equals("off")) {
                sw.off();
            } else if (params[1].equals("toggle")) {
                sw.act();
            } else {
                System.out.println("Invalid command parameter");
            }
        } else if (cmd.equals("stepgenerator")) {
            adapter.getCircuit().getElementById(params[0]).act();
        } else {
            if (cmd.length() > 0) {
                System.out.println("Invalid command " + cmd);
            }
        }
    }

    /**
     * Minden aramkorben levo elemet megbok d-szer
     * @param int d 
     */
    private void tickAll(int d) {
        StabilityObserver o = adapter.getCircuit().getStabilityObserver();
        int i = 0;
        for (i = 1; i <= d; i++) {
            if (tickCircuitElements(adapter.getCircuit())
                    && tickAllCompositesElements(adapter.getCircuit().getCompositeElements())) {
                break;
            }
        }
        display();
        if (i < d) {
            System.out.println("A kör stabil");
        } else {
            System.out.println("A kör nem stabil");
        }
    }

    /**
     * Megboki az aramkor elemeit
     * @param c
     * @return 
     */
    private boolean tickCircuitElements(Circuit c) {
        c.getStabilityObserver().prodAllElements(c.getElements());
        return c.getStabilityObserver().count();
    }

    /**
     * Megboki az osszes kompozit elemeit
     * @param composites
     * @return 
     */
    private boolean tickAllCompositesElements(ArrayList<Composite> composites) {
        boolean[] b = new boolean[composites.size()];
        int i = 0;
        for (Composite c : composites) {
            c.getStabilityObserver().prodAllElements(c.getElements());
            b[i++] = c.getStabilityObserver().count();
        }
        for (i--; i > 0; i--) {
            if (b[i] == false) {
                return false;
            }
        }
        return true;
    }

    /**
     * Megjeleniti a kijelzok ertekeit
     */
    private void display() {
        for (IElement e : adapter.getCircuit().getElements()) {
            e.show();
        }
    }

    /**
     * Kimeneti fajlt kezelo osztaly
     */
    private static class OutputHandler extends PrintStream {

        private String outputFile;

        public OutputHandler(String outputFile) {
            super(System.out);
            this.outputFile = outputFile;
            clearFile();
        }

        /**
         * Stdout-ra iras elott lementjuk fajlba a kimenetet
         * @param String s 
         */
        @Override
        public void println(String s) {
            try {
                FileWriter fw = new FileWriter(outputFile, true);
                fw.write(s + "\n");
                fw.close();
            } catch (Exception e) {
                System.out.print("");
            }
            getOut().println(s);
        }

        /**
         * Visszaadja a PrintStream-et
         * @return PrintStream
         */
        private PrintStream getOut() {
            return ((PrintStream) out);
        }
        
        /**
         * Inicializalaskor torli a kimeneti fajl tartalmat
         */
        private void clearFile() {
            try {
                FileWriter fw = new FileWriter(outputFile);
                fw.write("");
                fw.close();
            } catch (Exception e) {
            }
        }
    }
}
